package de.urwalking.legobaukasten;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.threed.jpct.Polyline;

import android.util.Log;


public class XMLParser
{
	InputStream xml = null;
	LegoRenderer source;
	
	float scale = 1.0f;
	float shiftX = 0;
	float shiftY = 0;
	
	public ArrayList<ArrayList<URWnode>> URWbranches = new ArrayList<ArrayList<URWnode>>();
	public ArrayList<ArrayList<URWedge>> URWedges = new ArrayList<ArrayList<URWedge>>();
	public ArrayList<ArrayList<URWnode>> URWshops = new ArrayList<ArrayList<URWnode>>();
	public ArrayList<URWleveledge> URWleveledges = new ArrayList<URWleveledge>();
	
	public int currentLevel = 0;
	
	public XMLParser(InputStream xml){
		this.xml = xml;
		this.source = source;
	}	
	
	private int parse(Node n, int parent)
	{
		
		if(n.getNodeName() == "#text")
		{
			return -1;
		}
		NamedNodeMap nodeMap = n.getAttributes();
		Node nType = nodeMap != null ? n.getAttributes().getNamedItem("type") : null;		
		boolean hasType = (nType != null) ? true : false;
		
		boolean addToList = true;
		
		int id = -1;
		
		if(nodeMap.getNamedItem("id") != null)
		{
			id = Integer.parseInt(nodeMap.getNamedItem("id").getNodeValue());
		}
		else
		{
			if(nodeMap.getNamedItem("scale") != null)
			{
				scale = Float.parseFloat(nodeMap.getNamedItem("scale").getNodeValue());
				
				if(nodeMap.getNamedItem("shiftX") != null) shiftX = Integer.parseInt(nodeMap.getNamedItem("shiftX").getNodeValue());
				if(nodeMap.getNamedItem("shiftY") != null) shiftY = Integer.parseInt(nodeMap.getNamedItem("shiftY").getNodeValue());
					
			}
			else
			{
				addToList = false;
				Log.d("lego", "id error");
			}
		}
		
		if(nodeMap.getNamedItem("storey") != null)
		{			
			currentLevel = Integer.parseInt(nodeMap.getNamedItem("storey").getNodeValue());
			URWbranches.add(new ArrayList<URWnode>());
			URWedges.add(new ArrayList<URWedge>());
			URWshops.add(new ArrayList<URWnode>());
			
			
		}
		
		if(addToList)
		{
			if(	nodeMap.getNamedItem("id") != null && 
				nodeMap.getNamedItem("source") != null &&
				nodeMap.getNamedItem("sink") != null)
			{
				URWedges.get(currentLevel).add(new URWedge(
						Integer.parseInt(nodeMap.getNamedItem("id").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("source").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("sink").getNodeValue())));
				
			}
			
			if(	nodeMap.getNamedItem("id") != null &&
				nodeMap.getNamedItem("x") != null &&
				nodeMap.getNamedItem("y") != null &&
				nodeMap.getNamedItem("type") != null)
			{
				if(nodeMap.getNamedItem("name") != null)
				{
					URWshops.get(currentLevel).add(new URWnode(
							Integer.parseInt(nodeMap.getNamedItem("id").getNodeValue()),
							(int)(Integer.parseInt(nodeMap.getNamedItem("x").getNodeValue()) * scale + shiftX),
							(int)(Integer.parseInt(nodeMap.getNamedItem("y").getNodeValue()) * scale + shiftY),
							nodeMap.getNamedItem("type").getNodeValue(),
							nodeMap.getNamedItem("name").getNodeValue()));
				}
				else
				{
					
					URWbranches.get(currentLevel).add(new URWnode(
							Integer.parseInt(nodeMap.getNamedItem("id").getNodeValue()),
							(int)(Integer.parseInt(nodeMap.getNamedItem("x").getNodeValue()) * scale + shiftX),
							(int)(Integer.parseInt(nodeMap.getNamedItem("y").getNodeValue()) * scale + shiftY)));
				}
			}
			
			if(	nodeMap.getNamedItem("id") != null &&
				nodeMap.getNamedItem("sourcenode") != null &&
				nodeMap.getNamedItem("sinknode") != null &&
				nodeMap.getNamedItem("sourcelevel") != null &&
				nodeMap.getNamedItem("sinklevel") != null &&
				nodeMap.getNamedItem("type") != null)
			{
				URWleveledges.add(new URWleveledge(
						Integer.parseInt(nodeMap.getNamedItem("id").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("sourcenode").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("sinknode").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("sourcelevel").getNodeValue()),
						Integer.parseInt(nodeMap.getNamedItem("sinklevel").getNodeValue()),
						nodeMap.getNamedItem("type").getNodeValue()));
			}
			
		}
		
		NodeList list = n.getChildNodes();
		for (int i = 0; i < list.getLength(); ++i)
		{
	        Node child = list.item(i);
	        int childIndex = parse(child, id);
		}
		
		return id;
	}
	
	
	public void parse()
	{
		String xmlData = "";
		BufferedReader fis = null;
		
		try {
			fis = new BufferedReader(new InputStreamReader(this.xml, "UTF-8"));
			int tempData;
			int counter = 0;
			final byte[] buf = new byte[1000];
			
			Writer writer = new StringWriter();
			char[] buffer = new char[1024];
			
			while ((tempData = fis.read(buffer)) != -1) 
            {
                writer.write(buffer, 0, tempData);
            }
			
			xmlData = writer.toString();
		} 
		catch (Exception e)
		{
			// TODO Auto-generated catch block
			Log.d("test", e.toString());
			e.printStackTrace();
		}
		finally
		{	
			try
			{
				if(fis != null)
				{
					fis.close();
				}
			}
			catch (Exception e)
			{
				// TODO Auto-generated catch block
				Log.d("test", e.toString());
				e.printStackTrace();
			}			
		}
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		Document doc = null;
		
		try
		{
			DocumentBuilder db = dbf.newDocumentBuilder();
			doc = db.parse(new InputSource(new ByteArrayInputStream(xmlData.getBytes("utf-8"))));
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		Node root = doc.getDocumentElement();
		
		parse(root, -1);
		
		initEdges();
	}
	
	public void initEdges()
	{
		for(int i = 0; i <= currentLevel; i++)
		{
			for(URWedge e : URWedges.get(i))
			{
				if(e.init(URWbranches.get(i))) Log.d("lego", "branch " + e.id + " initialized");
			}
		}
		
		for(URWleveledge e : URWleveledges)
		{
			if(e.initLevelEdge(URWbranches)) Log.d("lego", "ledge " + e.id + " initialized");
		}
	}

}
